/**  
  -- The Performance Driven Lime Project -- 

  A self adaptive tuple space for mobile agents and hosts by dynamic
  adapting tuple's replication policy.
  
  Copyright (C) 2008
  Xing Jiankuan, Pan Wenhui
  SAGroup of Tsinghua University

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details.

  You should have received this copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 */
package sagroup.pdlime;

/**
 * The policy that guide replications' creation and deletion.<br>
 * Two sub category of policies are defined here:<br>
 * <ul>
 * <li><b>Replication Policy: </b> Control whether replication should be
 * created. including FR, RC and SO.</li>
 * <li><b>Update Policy: </b> Control how to acquire replica's update. </li>
 * </ul>
 * This policy is populated through META tuple. Both policies are applied to one
 * type of tuples on the current tuple space only.
 * 
 * @author Xing Jiankuan
 * 
 */
class PDPolicy {

	final byte replicationPolicy;
	final byte updatePolicy;

	/**
	 * unknown policy
	 */
	static final byte UNKNOWN = 0x00;

	// replication policy constants.
	/**
	 * Full Replication, which means any host has a complete set of tuples of a
	 * type, masters or replicas.
	 */
	static final byte FR = 0x01;
	/**
	 * Store Originally, which means no replica is available, just as
	 * conventional Lime.
	 */
	static final byte SO = 0x02;
	/**
	 * Read and Cache, which means after reading a tuple, create a replica
	 * locally for future use.
	 */
	static final byte RC = 0x03;

	// update policy constants.
	/**
	 * A replica can acquire update from any other hosts.
	 */
	static final byte ANY = 0x10;
	/**
	 * A replica can only acquire update from the host holding the master.
	 */
	static final byte MASTER = 0x20;

	public PDPolicy(byte replicationPolicy, byte updatePolicy) {
		assert (updatePolicy == PDPolicy.MASTER)
				|| (updatePolicy == PDPolicy.ANY);
		assert (replicationPolicy == PDPolicy.SO)
				|| (replicationPolicy == PDPolicy.RC)
				|| (replicationPolicy == PDPolicy.FR);

		this.replicationPolicy = replicationPolicy;
		this.updatePolicy = updatePolicy;
	}

	/**
	 * Convert a byte containing both replication and target policy into
	 * PDPolicy instance.
	 * 
	 * @param compositePolicy
	 * @author Xing Jiankuan
	 */
	public PDPolicy(byte compositePolicy) {
		replicationPolicy = (byte) (compositePolicy & 0x0F);
		updatePolicy = (byte) (compositePolicy & 0xF0);
		assert (updatePolicy == PDPolicy.MASTER)
				|| (updatePolicy == PDPolicy.ANY);
		assert (replicationPolicy == PDPolicy.SO)
				|| (replicationPolicy == PDPolicy.RC)
				|| (replicationPolicy == PDPolicy.FR);
	}

	/**
	 * Convert the policy information to a single byte for storing and
	 * transfering in PDPolicyItem.
	 * 
	 * @author Xing Jiankuan
	 */
	public byte toSingleByte() {
		return (byte) (replicationPolicy | updatePolicy);
	}

	public byte getReplicationPolicy() {
		return replicationPolicy;
	}

	public byte getUpdatePolicy() {
		return updatePolicy;
	}

	public static byte getReplicationPolicy(byte compositePolicy) {
		return (byte) (compositePolicy & 0x0F);
	}

	public static byte getUpdatePolicy(byte compositePolicy) {
		return (byte) (compositePolicy & 0xF0);
	}

	public String toString() {
		String strRP, strUP;
		switch (replicationPolicy) {
		case SO:
			strRP = "SO";
			break;
		case RC:
			strRP = "RC";
			break;
		case FR:
			strRP = "FR";
			break;
		default:
			strRP = "UNKNOWN";
		}
		switch (updatePolicy) {
		case ANY:
			strUP = "ANY";
			break;
		case MASTER:
			strUP = "MASTER";
			break;
		default:
			strUP = "UNKNOWN";
		}
		return strRP + ":" + strUP;
	}
}